home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / xballs / xballs.c < prev   
C/C++ Source or Header  |  1995-05-03  |  9KB  |  553 lines

  1. /*
  2.  * Simple demo, animated (bouncing balls) background.
  3.  *
  4.  * Author: Bernard Hatt (bmh@terminus.ericsson.se)
  5.  *
  6.  * Camtec Electronics (Ericsson), Leicester, England, LE1 4SA
  7.  *
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <signal.h>
  12. #include <ctype.h>
  13. #include <sys/time.h>
  14.  
  15. #include <X11/X.h>
  16. #include <X11/Xlib.h>
  17. #include <X11/cursorfont.h>
  18.  
  19. Display *Disp;
  20. int Scr;
  21. Window Root;
  22. GC GcF,GcB;
  23.  
  24. #define NONE    0    /* not in a window */
  25. #define V    1    /* vertical */
  26. #define H    2    /* horizontal */
  27. #define B    3    /* ball */
  28.  
  29. #define MOUSEH    24
  30. #define MOUSEW    24
  31.  
  32. #define DEFRAD    16    /* default diameter */
  33. #define DEFNO    6
  34. #define SPEED    128
  35. #define SQLIMIT    (SPEED*SPEED/(20*20))    /* square of lower speed limit */
  36.  
  37. int dispx,dispy;
  38.  
  39. typedef struct rectangle_struct
  40. {
  41.     int x1,y1;    /* x and y coords top left */
  42.     int x2,y2;    /* x and y coords bottom right */
  43. } RECTANGLE;
  44.  
  45. int nor;
  46. RECTANGLE *rp=NULL;
  47.  
  48. typedef struct ball_struct
  49. {
  50.     int x,y;    /* x and y coords */
  51.     int dx,dy;    /* x and y velocity */
  52. } BALL;
  53.  
  54. int noballs=DEFNO;
  55. int radius=DEFRAD;
  56. BALL *bp;
  57. int coeff=85;
  58. int attop=100;
  59.  
  60. int backflag=0;
  61. int invertflag=0;
  62. int trailflag=0;
  63. int mouseflag=1;
  64. int sizeflag=0;
  65. int momentumflag=0;
  66. int interact=0;
  67. int mx,my,mn,mdx,mdy;
  68. int failed=0;
  69. int currmax=0;        /* current maximum number of windows */
  70.  
  71. char *getenv();
  72.  
  73. int lasttime;
  74.  
  75.  
  76. long lastsec=0;
  77. struct timezone tz={0,0};
  78. struct timeval tv;
  79. struct timeval tv2;
  80.  
  81. int
  82. rnd(n)
  83. int n;
  84. {
  85.     return((rand()/153)%n);
  86. }
  87.  
  88.  
  89. void    /* because Ultrix doesn't provide the nice SunOS usleep() */
  90. myusleep(val)
  91. int val;
  92. {
  93.     tv2.tv_sec=0;
  94.     tv2.tv_usec=val;
  95.  
  96.     select(0,NULL,NULL,NULL,&tv2);
  97. }
  98.  
  99. void
  100. dointr()
  101. {
  102.     clearballs();
  103.     exit(1);
  104. }
  105.  
  106. void
  107. Xerr()
  108. {
  109.     failed++;
  110. }
  111.  
  112. void
  113. Xfatal()
  114. {
  115.     exit(1);
  116. }
  117.  
  118. void
  119. randomball(i)
  120. int i;
  121. {
  122.     int x,y;
  123.     int dum;
  124.     int attempts;
  125.     attempts=0;
  126.     do
  127.     {
  128.         x=rnd(dispx);
  129.         y=rnd(dispy);
  130.         if(rnd(100)<attop)
  131.             y=0;
  132.         attempts++;
  133.         if(attempts>2000)
  134.         {
  135.             clearballs();
  136.             exit(1);
  137.         }
  138.     }
  139.     while(inwin(x,y,0,0,&dum)!=NONE);
  140.         bp[i].x=x;
  141.     bp[i].y=y;
  142.     bp[i].dx=rnd(SPEED)+(SPEED/2);
  143.     bp[i].dy=rnd(SPEED)+(SPEED/2);
  144.     switch(rnd(4))
  145.     {
  146.     case 0:
  147.         break;
  148.     case 1:
  149.         bp[i].dx=(0-bp[i].dx);
  150.         break;
  151.     case 2:
  152.         bp[i].dy=(0-bp[i].dy);
  153.         break;
  154.     case 3:
  155.         bp[i].dx=(0-bp[i].dx);
  156.         bp[i].dy=(0-bp[i].dy);
  157.         break;
  158.     }
  159. }
  160.  
  161. #ifdef SYSV
  162. # include <sys/timeb.h>
  163. #endif /*SYSV*/
  164. int
  165. gettime()
  166. {
  167. #ifdef SYSV
  168.     struct timeb    tb;
  169.  
  170.     ftime(&tb);
  171.     tv.tv_sec = tb.time;
  172.     tv.tv_usec = tb.millitm * 1000;
  173. #else /*SYSV*/
  174.     gettimeofday(&tv,&tz);
  175. #endif /*SYSV*/
  176.     if(lastsec==0)
  177.         lastsec=tv.tv_sec;
  178.     return((tv.tv_sec-lastsec)*100+(tv.tv_usec/10000));
  179. }
  180.  
  181. int
  182. inwin(x,y,dx,dy,n)
  183. int x,y,dx,dy;
  184. int *n;
  185. {
  186.     int i,diffx,diffy;
  187.     int coln;
  188.     coln=(-1);
  189.     if((x<0)||(x>dispx))
  190.         return(V);
  191.     if((y<0)||(y>dispy))
  192.         return(H);
  193.     for(i=0;i<nor;i++)
  194.     {
  195.         if((x<rp[i].x1)||(y<rp[i].y1)||(y>rp[i].y2)||(x>rp[i].x2))
  196.             continue;
  197.         coln=i;
  198.         break;
  199.     }
  200.     if(coln==(-1))
  201.     {
  202.         if(!interact)
  203.             return(NONE);
  204.         for(i=0;i<noballs;i++)
  205.         {
  206.             if(i==(*n))
  207.                 break;
  208.             diffx=(bp[i].x-x);
  209.             diffy=(bp[i].y-y);
  210.             if((diffx*diffx+diffy*diffy)<(radius*radius*4))
  211.             {
  212.                 (*n)=i;
  213.                 return(B);
  214.             }
  215.         }
  216.         return(NONE);
  217.     }
  218.     *n=coln;
  219.     x-=dx;
  220.     if((x<rp[i].x1)||(y<rp[i].y1)||(y>rp[i].y2)||(x>rp[i].x2))
  221.         return(V);
  222.     return(H);
  223. }
  224.  
  225. clearballs()
  226. {
  227.     int i;
  228.     XClearWindow(Disp,Root);
  229.     XFlush(Disp);
  230. }
  231.  
  232. void
  233. doballs()
  234. {
  235.     int i,n;
  236.     int newtime,td;
  237.     int dx,dy,x,y,nx,ny;
  238.     int redo;
  239.     int diffx,diffy;
  240.     int dumint;
  241.     Window dumwin;
  242.  
  243.     newtime=gettime();
  244.     td=newtime-lasttime;
  245.     if(td>20)
  246.         td=20;
  247.  
  248.     if(mouseflag)
  249.     {
  250.         XQueryPointer(Disp,Root,&dumwin,&dumwin,&nx,&ny,&dumint,&dumint,&dumint);
  251.         mdx=nx-mx;
  252.         mx=nx;
  253.         mdy=ny-my;
  254.         my=ny;
  255.         rp[mn].x1=mx-(MOUSEW/2);
  256.         rp[mn].y1=my-(MOUSEH/2);
  257.         rp[mn].x2=mx+(MOUSEW/2);
  258.         rp[mn].y2=my+(MOUSEH/2);
  259.     }
  260.  
  261.     for(i=0;i<noballs;i++)
  262.     {
  263.         if(backflag||trailflag)
  264.             XFillArc(Disp,Root,GcB,bp[i].x-(radius/2),bp[i].y-(radius/2),radius,radius,0,360*64);
  265.         else
  266.             XClearArea(Disp,Root,bp[i].x-(radius/2),bp[i].y-(radius/2),radius,radius,0);
  267.         redo=0;
  268.         if((bp[i].dx*bp[i].dx+bp[i].dy*bp[i].dy)<SQLIMIT)
  269.             redo=10;
  270.         do
  271.         {
  272.             dx=(td*bp[i].dx)/100;
  273.             dy=(td*bp[i].dy)/100;
  274.             if(redo>5)
  275.             {
  276.                 redo=0;
  277.                 randomball(i);
  278.             }
  279.  
  280.  
  281. /*            printf("coords are %d,%d [%d,%d]\n",bp[i].x,bp[i].y,bp[i].dx,bp[i].dy);*/
  282.             n=i;
  283.             switch(inwin(dx+bp[i].x,dy+bp[i].y,dx,dy,&n))
  284.             {
  285.             case NONE:
  286.                 bp[i].x+=dx;
  287.                 bp[i].y+=dy;
  288.                 redo=0;
  289.                 break;
  290.             case V:
  291.                 if((n==mn)&momentumflag)
  292.                 {
  293.                     bp[i].dx=mdx;
  294.                     bp[i].dy=mdy;
  295.                     bp[i].x+=dx;
  296.                     bp[i].y+=dy;
  297.                 }
  298.                 else
  299.                     bp[i].dx=(coeff*bp[i].dx)/100;
  300.  
  301.                 redo++;
  302.                 break;
  303.             case H:
  304.                 if((n==mn)&momentumflag)
  305.                 {
  306.                     bp[i].dy=mdy;
  307.                     bp[i].dx=mdx;
  308.                     bp[i].x+=dx;
  309.                     bp[i].y+=dy;
  310.                 }
  311.                 else
  312.                     bp[i].dy=(coeff*bp[i].dy)/100;
  313.  
  314.                 if(coeff!=100)
  315.                 {
  316. /*                    printf("[%d] y=%d dy=%d\n",i,bp[i].y,dy);*/
  317.                     if((bp[i].y>=(dispy-3))&&(dy<=5))
  318.                         redo=10;
  319.                     if((dx==0)&&(dy<=3))
  320.                         redo=10;
  321.                 }
  322.     
  323.                 redo++;
  324.                 break;
  325.             case B:
  326.                 diffx=bp[i].x-bp[n].x;
  327.                 diffy=bp[i].y-bp[n].y;
  328.                 
  329.                 break;
  330.             }
  331.             if(n==mn)
  332.                 redo=0;
  333.         }
  334.         while(redo);
  335.         bp[i].dy+=td;
  336.         
  337.         XFillArc(Disp,Root,GcF,bp[i].x-(radius/2),bp[i].y-(radius/2),radius,radius,0,360*64);
  338.         XFlush(Disp);
  339.     }
  340.     lasttime=newtime;
  341. }
  342.  
  343.  
  344. int
  345. getwins()
  346. {
  347.     int i;
  348.     Window dummy1,dummy2,*list;
  349.     XWindowAttributes WAttrib;
  350.     XEvent Event;
  351.  
  352.     unsigned int listsize;
  353.  
  354.     XQueryTree(Disp,Root,&dummy1,&dummy2,&list,&listsize);
  355.  
  356.     if((listsize+2)>currmax)
  357.     {
  358.         if(rp!=NULL)
  359.             free(rp);
  360.         currmax=listsize+20;
  361. /*        printf("currmax=%d\n",currmax);*/
  362.         rp=(RECTANGLE*)malloc(sizeof(RECTANGLE)*currmax);
  363.     }
  364.     else
  365.     {
  366.         while(XCheckWindowEvent(Disp,Root,SubstructureNotifyMask,&Event))
  367.         {
  368.             while(XCheckWindowEvent(Disp,Root,SubstructureNotifyMask,&Event));
  369.             lasttime=gettime();
  370.             myusleep(50*1000);
  371.         }
  372.     }
  373.     if(rp==NULL)
  374.     {
  375.         fprintf(stderr,"Failed to malloc %d bytes\n",sizeof(RECTANGLE)*listsize*2);
  376.         exit(1);
  377.     }
  378.  
  379.     nor=0;
  380.     for(i=0;i<listsize;i++)
  381.     {
  382.         failed=0;
  383.         XGetWindowAttributes(Disp,list[i],&WAttrib);
  384.         if((!failed)&&WAttrib.map_state==IsViewable)
  385.         {
  386.             rp[nor].x1=WAttrib.x;
  387.             rp[nor].y1=WAttrib.y;
  388.             rp[nor].x2=WAttrib.x+WAttrib.width;
  389.             rp[nor].y2=WAttrib.y+WAttrib.height;
  390. /*            printf("Window id 0x%x, x1=%d,y1=%d,x2=%d,y2=%d\n",list[nor],rp[nor].x1,rp[nor].y1,rp[nor].x2,rp[nor].y2);*/
  391.             nor++;
  392.         }
  393.     }
  394.     if(mouseflag)
  395.     {
  396.         mn=nor;
  397.         nor++;
  398.     }
  399.     XFree(list);
  400. }
  401.  
  402. main(argc,argv)
  403. int argc;
  404. char *argv[];
  405. {
  406.     unsigned long bg,fg;
  407.     char *dispname;
  408.     int i,j;
  409.     int x,y;
  410.     char *p;
  411.     XEvent Event;
  412.  
  413.     srand(time(0));
  414.     dispname=getenv("DISPLAY");
  415.     for(i=1;i<argc;i++)
  416.     {
  417.         p=argv[i];
  418.         if(*p++=='-')
  419.         {
  420.             switch(*p++)
  421.             {
  422.             case 'd':
  423.                 if(*p=='\0')
  424.                     dispname=argv[++i];
  425.                 else
  426.                     dispname=p;
  427.                 break;
  428.             case 'n':
  429.                 if(*p=='\0')
  430.                     noballs=atoi(argv[++i]);
  431.                 else
  432.                     noballs=atoi(p);
  433.                 break;
  434.             case 'r':
  435.                 if(*p=='\0')
  436.                     radius=atoi(argv[++i]);
  437.                 else
  438.                     radius=atoi(p);
  439.                 break;
  440.             case 'c':
  441.                 if(*p=='\0')
  442.                     coeff=atoi(argv[++i]);
  443.                 else
  444.                     coeff=atoi(p);
  445.                 break;
  446.             case 't':
  447.                 if(*p=='\0')
  448.                     attop=atoi(argv[++i]);
  449.                 else
  450.                     attop=atoi(p);
  451.                 break;
  452.             case 'b':
  453.                 backflag=(!backflag);
  454.                 break;
  455.             case 'i':
  456.                 invertflag=(!invertflag);
  457.                 break;
  458.             case 'm':
  459.                 mouseflag=(!mouseflag);
  460.                 break;
  461.             case 'M':
  462.                 momentumflag=(!momentumflag);
  463.                 break;
  464.             case 'I':
  465.                 interact=(!interact);
  466.                 break;
  467.             case 'l':
  468.                 trailflag=(!trailflag);
  469.                 break;
  470.             case 's':
  471.                 sizeflag=(!sizeflag);
  472.                 break;
  473.             default:
  474.                 /* usage */
  475.                 break;
  476.             }
  477.         }
  478.     }
  479.     if(coeff>100)
  480.         coeff=100;
  481.     if(coeff<0)
  482.         coeff=0;
  483.     coeff=(0-coeff);
  484.     bp=(BALL*)malloc(sizeof(BALL)*noballs);
  485.     if(bp==NULL)
  486.     {
  487.         fprintf(stderr,"Failed to malloc %d bytes\n",sizeof(BALL)*noballs);
  488.         exit(1);
  489.     }
  490.     Disp=XOpenDisplay(dispname);
  491.  
  492.     Root=XDefaultRootWindow(Disp);
  493.     Scr=DefaultScreen(Disp);
  494.  
  495.     clearballs();
  496.     if(noballs==0)
  497.         exit(0);
  498.  
  499.  
  500.     if(invertflag)
  501.     {
  502.         fg=BlackPixel(Disp,Scr);
  503.         bg=WhitePixel(Disp,Scr);
  504.     }
  505.     else
  506.     {
  507.         bg=BlackPixel(Disp,Scr);
  508.         fg=WhitePixel(Disp,Scr);
  509.     }
  510.  
  511.     GcF=XCreateGC(Disp,Root,0,0);
  512.     GcB=XCreateGC(Disp,Root,0,0);
  513.     XSetForeground(Disp,GcF,fg);
  514.     XSetForeground(Disp,GcB,bg);
  515.  
  516.     dispx=XDisplayWidth(Disp,Scr);
  517.     dispy=XDisplayHeight(Disp,Scr);
  518.  
  519.     if(sizeflag)
  520.         fprintf(stderr,"Screen size is %dX by %dY\n",dispx,dispy);
  521.  
  522.     if(backflag)
  523.     {
  524.         XSetWindowBackground(Disp,Root,bg);
  525.         XClearWindow(Disp,Root);
  526.     }
  527.     XSelectInput(Disp,Root,SubstructureNotifyMask);
  528.  
  529. /*    printf("Width and Height are %d,%d\n",dispx,dispy);*/
  530.     getwins();
  531.     XFlush(Disp);
  532.     for(i=0;i<noballs;i++)
  533.     {
  534.         randomball(i);
  535.     }
  536.     lasttime=gettime();
  537.     signal(SIGINT,dointr);
  538.     signal(SIGHUP,dointr);
  539.     signal(SIGTERM,dointr);
  540.     XSetErrorHandler(Xerr);
  541.     XSetIOErrorHandler(Xfatal);
  542.     while(1)
  543.     {
  544.         if(XCheckWindowEvent(Disp,Root,SubstructureNotifyMask,&Event))
  545.         {
  546.             getwins();
  547.         }
  548.         doballs();
  549.         myusleep(50*1000);
  550.     }
  551. }
  552.  
  553.